﻿
using EssentialDialogs;
using HimVoiceStudio.Audio;
using HimVoiceStudioCore;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.SharpZipLib.Zip;
using NAudio.Utils;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics.Eventing.Reader;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Windows.Input;
using System.Windows.Markup;
using Toaster;

namespace HimVoiceStudio
{
    public partial class FrmMain : Form
    {

        private ICSharpCode.AvalonEdit.TextEditor textEditor;


        private const string FileFormat = "Him Voice Studio Transcript|*.hvst";

        Toast Toast;
        public FrmMain()
        {
            InitializeComponent();
            Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
            textEditor = editorContainer1.textEditor;
            textEditor.TextChanged += TextEditor_TextChanged;

        }

        Graphics waveRenderTarget;
        Size waveRenderTargetSize;
        Pen waveformPen;
        BufferedGraphics waveRenderTargetBuffer;
        Brush fadeBrush;
        ImageList listIcons;
        private void FrmMain_Load(object sender, EventArgs e)
        {
            Toast = new Toast(this, new Font(this.Font.FontFamily, 22));
            listIcons = new ImageList();
            listIcons.Images.Add(Properties.Resources.folder);
            listIcons.Images.Add(Properties.Resources.item_npy);
            listIcons.Images.Add(Properties.Resources.item_audio);
            updateWindowTitle();
            if (Program.openingPath != null)
            {
                OpenInternal(Program.openingPath);
            }
            loadUserLogics();
            textEditor.Focus();
            waveRenderTarget = tblWaveForm.CreateGraphics();
            waveRenderTargetSize = tblWaveForm.ClientSize;
            waveformPen = Pens.Lime;
            fadeBrush = new SolidBrush(Color.FromArgb(72, Color.Black));
            tblWaveForm.SizeChanged += TblWaveForm_SizeChanged;
            waveRenderTargetBuffer = BufferedGraphicsManager.Current.Allocate(waveRenderTarget, new Rectangle(Point.Empty, waveRenderTargetSize));



        }

        private void TblWaveForm_SizeChanged(object sender, EventArgs e)
        {
            waveRenderTargetSize = tblWaveForm.ClientSize;
            waveRenderTargetBuffer.Dispose();
            waveRenderTargetBuffer = BufferedGraphicsManager.Current.Allocate(waveRenderTarget, new Rectangle(Point.Empty, waveRenderTargetSize));
        }

        #region EditorLogics
        private void TextEditor_TextChanged(object sender, EventArgs e)
        {
            Modified = true;
            if (CurrentFile == null && textEditor.Text == "")
            {
                Modified = false;
            }
            bool canUndo = textEditor.CanUndo;
            bool canRedo = textEditor.CanRedo;
            btnMnuUndo.Enabled = mnuUndo.Enabled = canUndo;
            btnMnuRedo.Enabled = mnuRedo.Enabled = canRedo;
        }
        private void editorContextMenu_Opening(object sender, CancelEventArgs e)
        {
            bool canCopyOrCut = textEditor.SelectionLength != 0;
            cmnuCopy.Enabled = cmnuCopy.Enabled = canCopyOrCut;
        }



        private void updateWindowTitle()
        {
            this.Text = (Modified ? "* " : "") + (CurrentFile == null ? "新建文件" : Path.GetFileName(CurrentFile)) + " - " + Application.ProductName;
        }

        private bool __modified = false;
        private bool Modified
        {
            get
            {
                return __modified;
            }
            set
            {
                __modified = value;
                updateWindowTitle();
            }
        }

        private string __currentFile = null;
        private string CurrentFile
        {
            get
            {
                return __currentFile;
            }

            set
            {
                __currentFile = value;
                updateWindowTitle();
            }
        }

        private void New()
        {
            if (CanExit())
            {
                CurrentFile = null;
                Modified = false;
                textEditor.Clear();
            }
        }

        private void Open()
        {
            if (CanExit())
            {
                var fileDialog = new OpenFileDialog() { Filter = FileFormat };
                if (fileDialog.ShowDialog(this) == DialogResult.OK)
                {
                    OpenInternal(fileDialog.FileName);
                }
            }
        }

        private void OpenInternal(String path)
        {
            Environment.CurrentDirectory = Path.GetDirectoryName(path);
            CurrentFile = path;
            textEditor.Clear();
            textEditor.Text = File.ReadAllText(CurrentFile);
            Modified = false;
        }

        private bool Save()
        {
            if (CurrentFile == null)
            {
                var fileDialog = new SaveFileDialog() { Filter = FileFormat };
                if (fileDialog.ShowDialog(this) == DialogResult.OK)
                {
                    CurrentFile = (fileDialog.FileName);
                    Environment.CurrentDirectory = Path.GetDirectoryName(fileDialog.FileName);

                }
                else
                {
                    return false;
                }
            }

            File.WriteAllText(CurrentFile, textEditor.Text);
            Modified = false;
            showMessage("保存成功");
            return true;
        }

        private void SaveAs()
        {
            var fileDialog = new SaveFileDialog() { Filter = FileFormat };
            if (fileDialog.ShowDialog(this) == DialogResult.OK)
            {
                File.WriteAllText(fileDialog.FileName, textEditor.Text);
                showMessage("已另存为 " + fileDialog.FileName);
                if (CurrentFile == null)
                {
                    CurrentFile = (fileDialog.FileName);
                    Environment.CurrentDirectory = Path.GetDirectoryName(fileDialog.FileName);
                    Modified = false;
                }
            }

        }

        private bool CanExit()
        {
            if (Modified)
            {
                var result = MessageBox.Show("当前文档已经修改，是否保存？", Application.ProductName, MessageBoxButtons.YesNoCancel);
                if (result == DialogResult.Cancel)
                {
                    return false;
                }
                else if (result == DialogResult.No)
                {
                    return true;
                }
                else
                {
                    return Save();
                }

            }
            return true;
        }

        private void mnuNewFile_Click(object sender, EventArgs e)
        {
            New();
        }

        private void mnuOpenFile_Click(object sender, EventArgs e)
        {
            Open();
        }

        private void mnuSaveFile_Click(object sender, EventArgs e)
        {
            Save();
        }

        private void mnuSaveAs_Click(object sender, EventArgs e)
        {
            SaveAs();
        }

        private void mnuExit_Click(object sender, EventArgs e)
        {
            if (CanExit())
            {
                this.FormClosing -= FrmMain_FormClosing;
                Application.Exit();
            }
        }

        private void mnuUndo_Click(object sender, EventArgs e)
        {
            textEditor.Undo();
        }

        private void mnuRedo_Click(object sender, EventArgs e)
        {
            textEditor.Redo();
        }
        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = !CanExit();
            }
            else
            {
                if (CurrentFile != null)
                {
                    Save();
                }
            }
        }

        private void showMessage(string message, int second = 1)
        {
            lblStatusMain.Text = message;
            messageClearCountDown = second * 10;
            messageTimer.Start();
        }

        private int messageClearCountDown = 0;
        private void messageTimer_Tick(object sender, EventArgs e)
        {
            messageClearCountDown--;
            if (messageClearCountDown <= 0)
            {
                lblStatusMain.Text = "就绪";
                messageTimer.Stop();
            }
        }

        private void cmnuCut_Click(object sender, EventArgs e)
        {
            textEditor.Cut();
        }

        private void cmnuCopy_Click(object sender, EventArgs e)
        {
            textEditor.Copy();
        }

        private void cmnuPaste_Click(object sender, EventArgs e)
        {
            textEditor.Paste();
        }

        private void cmnuSelectAll_Click(object sender, EventArgs e)
        {
            textEditor.SelectAll();
        }


        private void mnuHelp_Click(object sender, EventArgs e)
        {
            Form frm = new Form();
            frm.StartPosition = FormStartPosition.CenterParent;
            ElementHost eh = new ElementHost();
            EditorContainer editorContainer = new EditorContainer();
            editorContainer.textEditor.Text = Properties.Resources.语音合成标记语言;
            eh.Child = editorContainer;
            frm.Controls.Add(eh);
            eh.Dock = DockStyle.Fill;
            frm.Size = new System.Drawing.Size(640, 480);
            frm.FormBorderStyle = FormBorderStyle.Sizable;
            frm.ShowInTaskbar = false;
            frm.Text = "语法帮助";
            frm.StartPosition = FormStartPosition.Manual;
            frm.Left = this.Left + this.Width / 2 - frm.Width / 2;
            frm.Top = this.Top + this.Height / 2 - frm.Height / 2;
            frm.ShowIcon = false;
            frm.Show(this);
        }

        #endregion

        private void loadUserLogics()
        {
            loadEmoAndSplice();
            loadSpeakerList();
            initChapterList();
        }

        private void loadSpeakerList()
        {
            List<string> speakerList = null;
            ProgressDialog.RunWork(this, ps =>
            {
                ps.SetMessage("获取数据中");
                if (!ComposingService.IsServerUp(1000))
                {
                    ps.SetMessage("正在启动语音合成服务");
                    if (!ComposingService.TryStartServer(Path.Combine(Program.appPath, "assets", "gptsovits")))
                    {
                        throw new Exception("语音合成服务启动失败");
                    }
                }
                ps.SetMessage("获取数据中");
                speakerList = ComposingService.GetCachedSpeakerList();
            }, err =>
            {
                if (err == null)
                {

                }
                else
                {
                    MessageBox.Show(this, $"初始数据加载失败：{err.GetType().Name}：{err.Message}\r\n可以继续编辑脚本，但无法使用合成功能。");


                }
            });
        }

        private void loadEmoAndSplice()
        {
            ImageList imageList = new ImageList();
            imageList.Images.Add(Properties.Resources.folder);
            imageList.Images.Add(Properties.Resources.item_npy);
            imageList.Images.Add(Properties.Resources.item_audio);

            listEmotion.BeginUpdate();
            listEmotion.HideSelection = false;
            listEmotion.ImageList = imageList;
            loadEmotion(listEmotion, Program.PAssets.EmotionAssetRoot);
            listEmotion.EndUpdate();

            listSplices.BeginUpdate();
            listSplices.HideSelection = false;
            listSplices.ImageList = imageList;
            loadSplice(listSplices, Program.PAssets.SpliceAssetRoot);
            listSplices.EndUpdate();
        }
        private List<TreeNode> emotionNodeSeq = new List<TreeNode>();
        private List<TreeNode> spliceNodeSeq = new List<TreeNode>();
        private void loadEmotion(object node, EmoInfoNode node2)
        {
            Func<string, int, EmoInfoNode, TreeNode> addNode = null;
            if (node is TreeView tv)
            {
                addNode = (title, icon, tag) =>
                {
                    var n = tv.Nodes.Add(title);
                    n.ImageIndex = icon;
                    n.SelectedImageIndex = icon;
                    n.Tag = tag;
                    return n;
                };
            }
            if (node is TreeNode tn)
            {
                addNode = (title, icon, tag) =>
                {
                    var n = tn.Nodes.Add(title);
                    n.ImageIndex = icon;
                    n.SelectedImageIndex = icon;
                    n.Tag = tag;

                    return n;
                };
            }

            node2.subDirs.ForEach(n =>
            {
                var stn = addNode(n.displayName, 0, n);
                loadEmotion(stn, n);
            });
            node2.files.ForEach(n => emotionNodeSeq.Add(addNode(n.displayName, 1, n)));

        }

        private void loadSplice(object node, EmoInfoNode node2)
        {
            Func<string, int, EmoInfoNode, TreeNode> addNode = null;
            if (node is TreeView tv)
            {
                addNode = (title, icon, tag) =>
                {
                    var n = tv.Nodes.Add(title);
                    n.ImageIndex = icon;
                    n.SelectedImageIndex = icon;
                    n.Tag = tag;
                    return n;
                };
            }
            if (node is TreeNode tn)
            {
                addNode = (title, icon, tag) =>
                {
                    var n = tn.Nodes.Add(title);
                    n.ImageIndex = icon;
                    n.SelectedImageIndex = icon;
                    n.Tag = tag;

                    return n;
                };
            }

            node2.subDirs.ForEach(n =>
            {
                var stn = addNode(n.displayName, 0, n);
                loadEmotion(stn, n);
            });
            node2.files.ForEach(n => spliceNodeSeq.Add(addNode(n.displayName, 2, n)));

        }

        private void btnEmotionSearch_Click(object sender, EventArgs e)
        {
            findEmotionNext(txtEmotionSearch.Text);
        }
        private void findEmotionNext(string keyword)
        {
            keyword = keyword.Trim();
            if (string.IsNullOrEmpty(keyword)) { return; }
            TreeNode currentNode = listEmotion.SelectedNode;
            int startIndex = 0;
            if (currentNode != null)
            {
                if (emotionNodeSeq.Contains(currentNode))
                {

                    startIndex = emotionNodeSeq.IndexOf(currentNode) + 1;
                }
            }
            bool contains = emotionNodeSeq.Any(q => q.Text.Contains(keyword));
            if (!contains)
            {
                Toast.ShowMessage("查找无结果");
                return;
            }
            for (int i = startIndex; i < emotionNodeSeq.Count; i++)
            {
                if (emotionNodeSeq[i].Text.Contains(keyword))
                {
                    listEmotion.SelectedNode = emotionNodeSeq[i];
                    return;
                }
            }
            Toast.ShowMessage("查找已到底，请从头开始查找");
        }

        private void listEmotion_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (emotionNodeSeq.Contains(e.Node))
            {

                txtEmotionSelected.ReadOnly = false;
                var obj = e.Node.Tag as EmoInfoNode;
                txtEmotionSelected.Text = obj.indexName;
                txtEmotionSelected.ReadOnly = true;
            }
        }


        private void btnPreview_Click(object sender, EventArgs e)
        {
            // 获取必要信息
            string text = textEditor.Text;
            int selectionStart = textEditor.SelectionStart;
            int selectionEnd = textEditor.SelectionLength + selectionStart;

            // 开始计算选中内容前面的内容
            int cursor = selectionStart;
            if (cursor >= text.Length)
            {
                return;
            }
            while (cursor > 0 && text[cursor] != '\n')
            {
                cursor--;
            }
            string precondition = text.Substring(0, cursor);
            // 获取选中的内容
            cursor = selectionEnd;
            while (cursor < text.Length && text[cursor] != '\n')
            {
                cursor++;
            }
            string selectedContent = text.Substring(precondition.Length, cursor - precondition.Length);

            try
            {
                PlayContent(new TranscriptEngine().EvaluatePartial(precondition, selectedContent));
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }

        private void btnLoadParam_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            // 获取必要信息
            string text = textEditor.Text;
            int selectionStart = textEditor.SelectionStart;
            int selectionEnd = textEditor.SelectionLength + selectionStart;

            // 开始计算选中内容前面的内容
            int cursor = selectionStart;
            if (cursor >= text.Length)
            {
                return;
            }
            while (cursor > 0 && text[cursor] != '\n')
            {
                cursor--;
            }
            string precondition = text.Substring(0, cursor);
            // 获取选中的内容
            cursor = selectionEnd;
            while (cursor < text.Length && text[cursor] != '\n')
            {
                cursor++;
            }
            string selectedContent = text.Substring(precondition.Length, cursor - precondition.Length);

            try
            {
                var data = new TranscriptEngine().EvaluatePartial(precondition, selectedContent);
                if (data.Count == 1 && data[0] is YieldComposeException yex)
                {
                    showParam(yex.param);
                }
                else
                {
                    showMessage("只能获取单条内容的参数");
                }
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }


        }

        private void showParam(ComposingParam param)
        {
            txtEmotionSelected.Text = param.emotion;
            numSeed.Value = param.seed;
            foreach (var item in emotionNodeSeq.Where(n => param.emotion == (n.Tag as EmoInfoNode)?.indexName))
            {
                listEmotion.SelectedNode = item;
                break;
            }
        }

        


        private void mnuLintErr_Click(object sender, EventArgs e)
        {
            string text = textEditor.Text;
            TranscriptEngine engine = new TranscriptEngine();
            try
            {
                engine.Validate(text);
                Toast.ShowMessage("没有发现错误");
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"发现错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }

        AudioPlayer __player = null;


        private void PlayContent(List<BaseParamYieldException> data)
        {
            btnPreview.Enabled = false;
            btnPlayAll.Enabled = false;
            cmnuPreview.Enabled = false;
            btnPreviewWithParam.Enabled = false;
            lblStatusPlayback.Text = "合成中";
            composingThread.RunWorkerAsync(data);

        }

        private void AwaitComposeAsync(List<BaseParamYieldException> data, Action<int, int> progressCallback, Action<List<ISampleProvider>, Exception> callback)
        {
            var thread = new Thread(() =>
            {
                try
                {
                    List<ISampleProvider> providers = new List<ISampleProvider>();
                    int count = 0;
                    foreach (var item in data)
                    {
                        if (item is YieldComposeException compose)
                        {
                            var prv = new DisposableWaveToSampleProvider(new WaveFileReader(ComposingService.ComposeAndGetPath(compose.text, compose.param)));
                            if (compose.param.spliceParam != null)
                            {
                                prv = prv.Splice(compose.param.spliceParam.start, compose.param.spliceParam.end);
                            }
                            providers.Add(prv);
                        }
                        if (item is YieldDelayException delay)
                        {
                            providers.Add(new SilenceProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 1)).ToSampleProvider().Take(TimeSpan.FromMilliseconds(delay.delayMs)));
                        }
                        if (item is YieldInsertFile insert)
                        {
                            var key = insert.fileName;
                            var node = Program.PAssets.GetSpliceAudio(key);
                            if (node != null)
                            {
                                var fileName = node.FilePath;
                                if (!File.Exists(fileName))
                                {
                                    throw new ArgumentException(key + "不是一个有效的音频切片ID");
                                }
                            }
                            var prv = new DisposableWaveToSampleProvider(new WaveFileReader(
                               node.FilePath));
                            if (insert.spliceParam != null)
                            {
                                prv = prv.Splice(insert.spliceParam.start, insert.spliceParam.end);
                            }
                            providers.Add(prv);
                        }
                        progressCallback(count, data.Count);
                        count++;
                    }
                    callback(providers, null);
                }
                catch (Exception ex)
                {
                    callback(null, ex);
                }
            });
            thread.Start();
            thread.Join();
        }

        private void composingThread_DoWork(object sender, DoWorkEventArgs e)
        {
            List<BaseParamYieldException> data = (List<BaseParamYieldException>)e.Argument;

            AwaitComposeAsync(data,
                (count, total) =>
                {
                    composingThread.ReportProgress(count * 100 / total);
                },
                (result, err) =>
                {
                    if (result != null)
                    {
                        e.Result = result;
                    }
                    else
                    {
                        e.Result = err;
                    }
                }
            );


        }
        private void composingThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            numProgressMain.Value = e.ProgressPercentage;
        }

        private void composingThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btnPreview.Enabled = true;
            btnPlayAll.Enabled = true;
            cmnuPreview.Enabled = true;
            btnPreviewWithParam.Enabled = true;
            if (e.Result == null) { return; }
            if (e.Result is List<ISampleProvider> results)
            {
                if (results.Count == 0)
                {

                    numProgressMain.Value = 0;
                    lblStatusPlayback.Text = "已停止";
                    showMessage("合成结果为空，无需播放。", 3);
                    return;
                }
                numProgressMain.Value = 100;
                PlayAudio(new ConcatenatingDisposableSampleProvider(results));
                showMessage("合成成功", 3);
            }
            if (e.Result is Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
                numProgressMain.Value = 0;
                lblStatusPlayback.Text = "已停止";
            }

        }

        public void PlayAudio(ISampleProvider provider)
        {
            if (__player != null)
            {
                try
                {
                    __player?.Stop();
                }
                catch { }
            }
            __player = new AudioPlayer(provider);
            __player.OnStop += Player_OnStop;
            __player.OnSample += __player_OnSample;
            __player.Play();
            btnStop.Enabled = true;

            lblStatusPlayback.Text = "播放中";
        }

        DateTime lastUpdate = DateTime.Now;

        private void __player_OnSample(object sender, SampleReceivedEventArgs srea)
        {
            float[] e = srea.Samples;
            if ((DateTime.Now - lastUpdate).TotalMilliseconds < 25)
            {
                return;
            }
            Invoke(new Action(() =>
            {
                //waveRenderTargetBuffer.Graphics.Clear(Color.Black);

                Graphics g = waveRenderTargetBuffer.Graphics;
                g.FillRectangle(fadeBrush, 0, 0, waveRenderTargetSize.Width, waveRenderTargetSize.Height);
                float lx = -10, ly = waveRenderTargetSize.Height / 2;
                for (int i = 0; i < e.Length; i++)
                {
                    float nx = ((float)i) / ((float)e.Length) * ((float)waveRenderTargetSize.Width);
                    float ny = waveRenderTargetSize.Height / 2f - e[i] * (float)(waveRenderTargetSize.Height) * 0.9f;
                    g.DrawLine(waveformPen, lx, ly, nx, ny);
                    lx = nx;
                    ly = ny;
                }
                waveRenderTargetBuffer.Render();
            }));

        }

        private void Player_OnStop(object sender, EventArgs e)
        {
            var currentPlayer = sender as AudioPlayer;
            currentPlayer.Dispose();
            if (currentPlayer == __player)
            {
                __player = null;
                btnStop.Enabled = false;
                numProgressMain.Value = 0;
                lblStatusPlayback.Text = "已停止";
            }
            waveRenderTargetBuffer.Graphics.Clear(Color.Black);
            waveRenderTargetBuffer.Render();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            try
            {
                __player?.Stop();
            }
            catch { }
        }
        private void mnuExport_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "音频文件|*.wav";
            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                string fileName = saveFileDialog.FileName;
                string text = textEditor.Text;
                ProgressDialog.RunWork(this, ps =>
                {
                    ps.SetIndetermine(true);
                    ps.SetMessage("正在编译脚本...");
                    var data = new TranscriptEngine().EvaluateAll(text);
                    if (data.Count == 0)
                    {
                        throw new Exception("合成结果是空的。");
                    }
                    ps.SetMessage("开始合成...");

                    SaveContentTo(data, fileName, (p) =>
                    {
                        ps.SetProgress(p.current, p.total);
                    });
                    ps.SetMessage("完成！");
                    Thread.Sleep(500);
                }, err =>
                {
                    if (err is TranscriptSyntaxException ex)
                    {
                        MessageBox.Show(this, $"发现错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
                        return;
                    }
                    if (err != null)
                    {
                        MessageBox.Show(this, $"合成错误：{err.GetType().Name}：{err.Message}");
                        return;
                    }
                    showMessage("合成完成");
                });
            }
        }

        private void mnuSetApiUrl_Click(object sender, EventArgs e)
        {

        }

        private void FrmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            composingThread.CancelAsync();
        }

        private void listEmotion_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (emotionNodeSeq.Contains(e.Node))
            {
                listEmotion.SelectedNode = e.Node;
                EmoInfoNode emoInfoNode = e.Node.Tag as EmoInfoNode;
                if (e.Button == MouseButtons.Right)
                {
                    selectedItemType = SelectedItemType.EmotionReference;
                    selectedItemIndex = emoInfoNode.indexName;
                    mnuEmoReference.Show(listEmotion, e.Location);
                }
            }
        }

        enum SelectedItemType
        {
            EmotionReference,
            AudioSplice
        }

        private string selectedItemIndex = null;
        private SelectedItemType selectedItemType = SelectedItemType.EmotionReference;

        private void mnuPreviewSelectedAudio_Click(object sender, EventArgs e)
        {
            string audioPath = null;
            if (selectedItemType == SelectedItemType.AudioSplice)
            {
                audioPath = Program.PAssets.GetSpliceAudio(selectedItemIndex).FilePath;
            }
            if (selectedItemType == SelectedItemType.EmotionReference)
            {
                audioPath = Program.PAssets.GetEmotionReference(selectedItemIndex).ReferenceAudio;
            }
            if (audioPath == null)
            {
                Toast.ShowMessage("当前项目无音频预览");
                return;
            }
            PlayAudio((ISampleProvider)new AudioFileReader(audioPath));
        }

        private bool insertBeforeCurrentLine(string str)
        {
            try
            {
                TextSegment textSegment = new TextSegment() { StartOffset = 0, Length = 0 };
                do
                {
                    string text = textEditor.Text;
                    int selectionStart = textEditor.SelectionStart;
                    if (selectionStart >= text.Length)
                    {
                        textSegment.StartOffset = text.Length;
                        textSegment.Length = 0;
                        break;
                    }
                    // 获取选中的内容
                    int cursor = selectionStart;
                    while (cursor > 0 && text[cursor] != '\n')
                    {
                        cursor--;
                    }
                    if (text[cursor] == '\n') { cursor++; }
                    if (cursor <= 0)
                    {
                        break;
                    }
                    textSegment.StartOffset = cursor;
                    textSegment.EndOffset = cursor;
                } while (false);

                textEditor.Document.Replace(textSegment, str + "\n");
                textEditor.Select(textSegment.StartOffset + str.Length + 1, 0);
                return true;
            }
            catch (Exception ex)
            {
                while (true)
                {
                    try
                    {
                        Clipboard.SetText(str);
                        break;
                    }
                    catch
                    {
                        Thread.Sleep(20);
                    }
                }

                Toast.ShowMessage("此处不能插入内容，已复制到剪切板");
                return false;
            }
        }

        private bool ReplaceLineAboveOrJustInsert(string applyingArguments, Func<string, bool> lineMatching, Func<string, bool> stopMatchingPredications, int maxMatchingDistance = 32, bool insertWhenNotFound = true)
        {
            try
            {
                string text = textEditor.Text;
                int selectionStart = textEditor.SelectionStart;

                // 获取当前光标所在行号
                int currentLine = textEditor.Document.GetLineByOffset(selectionStart).LineNumber;

                // 记录要替换的行号，初始为-1表示未找到
                int lineToReplace = -1;

                // 向上搜索
                for (int i = 1; i <= maxMatchingDistance; i++)
                {
                    int checkLine = currentLine - i;

                    // 检查是否到达文档开头
                    if (checkLine < 1)
                        break;

                    // 获取检查行的文本
                    DocumentLine line = textEditor.Document.GetLineByNumber(checkLine);
                    string lineText = text.Substring(line.Offset, line.Length);

                    // 优先检查停止条件
                    if (stopMatchingPredications(lineText))
                        break;

                    // 检查是否匹配替换条件
                    if (lineMatching(lineText))
                    {
                        lineToReplace = checkLine;
                        break;
                    }
                }

                if (lineToReplace != -1)
                {
                    // 找到匹配行，进行替换
                    DocumentLine line = textEditor.Document.GetLineByNumber(lineToReplace);
                    TextSegment textSegment = new TextSegment() { StartOffset = line.Offset, Length = line.Length };

                    // 替换行内容
                    textEditor.Document.Replace(textSegment, applyingArguments);
                    var lineAdditions = applyingArguments.Count(l => l == '\n');
                    if (lineAdditions > 0)
                    {
                        currentLine += lineAdditions;
                    }
                    line = textEditor.Document.GetLineByNumber(currentLine);

                    // 将光标移动到该行开头
                    textEditor.Select(line.Offset, 0);
                    return true;
                }
                else
                {
                    if (insertWhenNotFound)
                    {

                        // 未找到匹配行，直接在当前行上方插入
                        return insertBeforeCurrentLine(applyingArguments);
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                // 异常处理，复制到剪贴板
                while (true)
                {
                    try
                    {
                        Clipboard.SetText(applyingArguments);
                        break;
                    }
                    catch
                    {
                        Thread.Sleep(20);
                    }
                }

                Toast.ShowMessage("此处不能插入内容，已复制到剪切板");
                return false;
            }
        }

        private void mnuApplyEmoOrAudio_Click(object sender, EventArgs e)
        {

            if (selectedItemType == SelectedItemType.AudioSplice)
            {
                insertBeforeCurrentLine("# 语音切片：" + Program.PAssets.GetByIndex(selectedItemIndex).displayName + "\n[sfx " + selectedItemIndex + "]");
            }

            if (selectedItemType == SelectedItemType.EmotionReference)
            {

                setLineReferEmo(selectedItemIndex);
            }
        }
        Random rnd = new Random();
        private void btnSeedRnd_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            numSeed.Value = rnd.Next(0, 2147483647);
        }

        private void btnSeedGacha_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            // 获取必要信息
            string text = textEditor.Text;
            int selectionStart = textEditor.SelectionStart;
            int selectionEnd = textEditor.SelectionLength + selectionStart;

            // 开始计算选中内容前面的内容
            int cursor = selectionStart;
            if (cursor >= text.Length)
            {
                return;
            }
            while (cursor > 0 && text[cursor] != '\n')
            {
                cursor--;
            }
            string precondition = text.Substring(0, cursor);
            // 获取选中的内容
            cursor = selectionEnd;
            while (cursor < text.Length && text[cursor] != '\n')
            {
                cursor++;
            }
            string selectedContent = text.Substring(precondition.Length, cursor - precondition.Length);

            try
            {
                var data = new TranscriptEngine().EvaluatePartial(precondition, selectedContent);

                if (data.Count == 1 && data[0] is YieldComposeException yex)
                {
                    showGachaWindow(yex);
                }
                else
                {
                    Toast.ShowMessage("无法对多条内容同时合成");
                }
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }

        private void showGachaWindow(YieldComposeException param)
        {
            if (!string.IsNullOrEmpty(txtEmotionSelected.Text))
            {
                param.param.emotion = txtEmotionSelected.Text;
            }
            using (FrmGacha frmGacha = new FrmGacha(param))
            {
                frmGacha.StartPosition = FormStartPosition.CenterParent;

                if (frmGacha.ShowDialog(this) == DialogResult.Yes)
                {
                    setCurrentLineSeed(frmGacha.chosenSeed + "");
                }
            }
        }

        private void setCurrentLineSeed(String seedStr)
        {
            var strToInsert = "[seed " + seedStr + "]";
            ReplaceLineAboveOrJustInsert(strToInsert, l => l.Trim().StartsWith("[seed "), l =>
            {
                var l2 = l.Trim();
                if (l2.Length == 0) { return false; }
                if (l2.StartsWith("[setseed ") || l2.StartsWith("[sfx") || l2.StartsWith("[="))
                {
                    return true;
                }
                if (l2.StartsWith("#") || l2.StartsWith("["))
                {
                    return false;
                }
                return true;
            });
        }


        private void btnSetSeed_Click(object sender, EventArgs e)
        {
            setCurrentLineSeed(numSeed.Value + "");
        }

        private void setLineReferEmo(string emoParam)
        {
            var param = emoParam;
            var emo = Program.PAssets.GetByIndex(param);
            if (emo == null)
            {
                if (param != "default_emo.npz")
                {
                    Toast.ShowMessage("无效的提示档名称");
                    return;
                }
                else
                {
                    insertBeforeCurrentLine("[emo default_emo.npz]");
                }
            }

            var emoLine = "[emo " + param + "]";
            var commentLine = "# 情感参考：" + Program.PAssets.GetByIndex(param).displayName;
            var codeInsertResult = ReplaceLineAboveOrJustInsert(emoLine, s => s.Trim().StartsWith("[emo "), l =>
            {
                var l2 = l.Trim();
                if (l2.Length == 0) { return false; }
                if (l2.StartsWith("[setemo ") || l2.StartsWith("[defemo ") || l2.StartsWith("[sfx") || l2.StartsWith("[="))
                {
                    return true;
                }
                if (l2.StartsWith("#") || l2.StartsWith("["))
                {
                    return false;
                }
                return true;
            });
            if (codeInsertResult)
            {
                bool hasFoundEmoLine = false;
                bool hasMissedEmoLine = false;

                var replaceCommentResult = ReplaceLineAboveOrJustInsert(commentLine, s =>
                {
                    var l2 = s.Trim();
                    if (hasFoundEmoLine)
                    {
                        if (s.StartsWith("# 情感参考："))
                        {
                            return true;
                        }
                        else
                        {
                            hasMissedEmoLine = true;
                        }
                    }
                    if (s.StartsWith("[emo "))
                    {
                        hasFoundEmoLine = true;
                    }
                    return false;
                }, l =>
                {
                    return hasMissedEmoLine;
                }, insertWhenNotFound: false);
                // 没找到配套的注释
                if (replaceCommentResult == false)
                {
                    ReplaceLineAboveOrJustInsert(commentLine + "\r\n" + emoLine, s => s.Trim().StartsWith("[emo "), l =>
                    {
                        var l2 = l.Trim();
                        if (l2.Length == 0) { return false; }
                        if (l2.StartsWith("[setemo ") || l2.StartsWith("[defemo ") || l2.StartsWith("[sfx") || l2.StartsWith("[="))
                        {
                            return true;
                        }
                        if (l2.StartsWith("#") || l2.StartsWith("["))
                        {
                            return false;
                        }
                        return true;
                    });
                }
            }
            else
            {
                // 异常处理，复制到剪贴板
                while (true)
                {
                    try
                    {
                        Clipboard.SetText(commentLine + "\r\n" + emoLine);
                        break;
                    }
                    catch
                    {
                        Thread.Sleep(20);
                    }
                }

                Toast.ShowMessage("此处不能插入内容，已复制到剪切板");
            }
        }

        private void btnSetParam_Click(object sender, EventArgs e)
        {
            setLineReferEmo(txtEmotionSelected.Text);


        }

        private void btnPreviewWithParam_Click(object sender, EventArgs e)
        {
            // 获取必要信息
            string text = textEditor.Text;
            int selectionStart = textEditor.SelectionStart;
            int selectionEnd = textEditor.SelectionLength + selectionStart;

            // 开始计算选中内容前面的内容
            int cursor = selectionStart;
            if (cursor >= text.Length)
            {
                return;
            }
            while (cursor > 0 && text[cursor] != '\n')
            {
                cursor--;
            }
            string precondition = text.Substring(0, cursor);
            // 获取选中的内容
            cursor = selectionEnd;
            while (cursor < text.Length && text[cursor] != '\n')
            {
                cursor++;
            }
            string selectedContent = text.Substring(precondition.Length, cursor - precondition.Length);

            try
            {
                var data = new TranscriptEngine().EvaluatePartial(precondition, selectedContent);
                if (data.Count == 1 && data[0] is YieldComposeException yex)
                {
                    yex.param.seed = (int)numSeed.Value;
                    yex.param.emotion = string.IsNullOrEmpty(txtEmotionSelected.Text) ? null : txtEmotionSelected.Text;
                    PlayContent(new List<BaseParamYieldException>() { yex });

                }
                else
                {
                    Toast.ShowMessage("无法对多条内容同时合成");
                }
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }

        private void listSplices_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (spliceNodeSeq.Contains(e.Node))
            {
                EmoInfoNode emoInfoNode = e.Node.Tag as EmoInfoNode;
                txtSelectedSplice.ReadOnly = false;
                txtSelectedSplice.Text = emoInfoNode.indexName;
                txtSelectedSplice.ReadOnly = true;
            }
        }

        private void listSplices_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (spliceNodeSeq.Contains(e.Node))
            {
                listSplices.SelectedNode = e.Node;
                EmoInfoNode emoInfoNode = e.Node.Tag as EmoInfoNode;
                if (e.Button == MouseButtons.Right)
                {
                    selectedItemType = SelectedItemType.AudioSplice;
                    selectedItemIndex = emoInfoNode.indexName;
                    mnuEmoReference.Show(listEmotion, e.Location);
                }
            }
        }

        private void btnInsertSplice_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtSelectedSplice.Text))
            {
                return;
            }
            var selectedItemIndex = txtSelectedSplice.Text;
            insertBeforeCurrentLine("# 语音切片：" + Program.PAssets.GetByIndex(selectedItemIndex).displayName + "\n[sfx " + selectedItemIndex + "]");
        }

        private void btnSpliceSearch_Click(object sender, EventArgs e)
        {
            var keyword = txtSpliceSearch.Text;
            keyword = keyword.Trim();
            if (string.IsNullOrEmpty(keyword)) { return; }
            TreeNode currentNode = listSplices.SelectedNode;
            int startIndex = 0;
            if (currentNode != null)
            {
                if (spliceNodeSeq.Contains(currentNode))
                {

                    startIndex = spliceNodeSeq.IndexOf(currentNode) + 1;
                }
            }
            bool contains = spliceNodeSeq.Any(q => q.Text.Contains(keyword));
            if (!contains)
            {
                Toast.ShowMessage("查找无结果");
                return;
            }
            for (int i = startIndex; i < spliceNodeSeq.Count; i++)
            {
                if (spliceNodeSeq[i].Text.Contains(keyword))
                {
                    listSplices.SelectedNode = spliceNodeSeq[i];
                    return;
                }
            }
            Toast.ShowMessage("查找已到底，请从头开始查找");
        }


        WaveOut btbgmOut = null;
        private void 蓝牙耳机模式ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (btbgmOut == null)
            {
                ISampleProvider btbgm = new SignalGenerator()
                {
                    Type = SignalGeneratorType.Pink,
                    Gain = Decibels.DecibelsToLinear(-60)
                };
                btbgmOut = new WaveOut();
                btbgmOut.Init(btbgm);
                btbgmOut.Play();
                this.Disposed += disposeCleanBtBgmOut;
                蓝牙耳机模式ToolStripMenuItem.Checked = true;
            }
            else
            {
                btbgmOut.Stop();
                btbgmOut.Dispose();
                this.Disposed -= disposeCleanBtBgmOut;

                蓝牙耳机模式ToolStripMenuItem.Checked = false;
            }
        }

        private void disposeCleanBtBgmOut(object sender, EventArgs e)
        {
            btbgmOut.Dispose();
        }

        private void 裁剪音频片段ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // 获取必要信息
            string text = textEditor.Text;
            int selectionStart = textEditor.SelectionStart;
            int selectionEnd = textEditor.SelectionLength + selectionStart;


            // 开始计算选中内容前面的内容
            int cursor = selectionStart;
            if (cursor >= text.Length)
            {
                return;
            }
            while (cursor > 0 && text[cursor] != '\n')
            {
                cursor--;
            }
            string precondition = text.Substring(0, cursor);
            // 获取选中的内容
            cursor = selectionEnd;
            while (cursor < text.Length && text[cursor] != '\n')
            {
                cursor++;
            }
            string selectedContent = text.Substring(precondition.Length, cursor - precondition.Length);

            try
            {
                var data = new TranscriptEngine().EvaluatePartial(precondition, selectedContent);
                if (data.Count != 1)
                {
                    showMessage("无法裁剪多条内容，或者没有选中可裁剪的内容。");
                    return;
                }

                var oneData = data[0];
                if (oneData is YieldComposeException || oneData is YieldInsertFile)
                {
                    String targetFile = null;
                    SpliceParam spliceParam = null;
                    ProgressDialog.RunWork(this, ps =>
                    {
                        ps.SetMessage("正在合成音频…");
                        if (oneData is YieldComposeException compose)
                        {
                            targetFile = ComposingService.ComposeAndGetPath(compose.text, compose.param);
                            spliceParam = compose.param.spliceParam;
                        }
                        if (oneData is YieldInsertFile file)
                        {
                            targetFile = Program.PAssets.GetSpliceAudio(file.fileName).FilePath;
                            spliceParam = file.spliceParam;
                        }
                    }, err =>
                    {
                        if (err != null)
                        {
                            MessageBox.Show(this, "准备音频失败");
                            return;
                        }
                        var result = FrmCutAudio.ShowCutWindow(this, targetFile, spliceParam);
                        if (result != null)
                        {

                            ReplaceLineAboveOrJustInsert($"[splice {result.start:0.00}-{result.end:0.00}]", l => l.Trim().StartsWith("[splice "), l =>
                            {
                                var l2 = l.Trim();
                                if (l2.Length == 0) { return false; }
                                if (l2.StartsWith("[sfx") || l2.StartsWith("[="))
                                {
                                    return true;
                                }
                                if (l2.StartsWith("#") || l2.StartsWith("["))
                                {
                                    return false;
                                }

                                return true;
                            });

                        }
                    });
                }
                else
                {
                    showMessage("无法裁剪当前内容");
                    return;
                }
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }

        private void mnuExportPartial_Click(object sender, EventArgs e)
        {
            // 获取必要信息
            string text = textEditor.Text;
            int selectionStart = textEditor.SelectionStart;
            int selectionEnd = textEditor.SelectionLength + selectionStart;

            // 开始计算选中内容前面的内容
            int cursor = selectionStart;
            if (cursor >= text.Length)
            {
                return;
            }
            while (cursor > 0 && text[cursor] != '\n')
            {
                cursor--;
            }
            string precondition = text.Substring(0, cursor);
            // 获取选中的内容
            cursor = selectionEnd;
            while (cursor < text.Length && text[cursor] != '\n')
            {
                cursor++;
            }
            string selectedContent = text.Substring(precondition.Length, cursor - precondition.Length);

            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "音频文件|*.wav";
            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                string fileName = saveFileDialog.FileName;
                ProgressDialog.RunWork(this, ps =>
                {
                    ps.SetIndetermine(true);
                    ps.SetMessage("正在编译脚本...");
                    var data = new TranscriptEngine().EvaluatePartial(precondition,selectedContent);
                    if (data.Count == 0)
                    {
                        throw new Exception("合成结果是空的。");
                    }
                    ps.SetMessage("开始合成...");
                    SaveContentTo(data, fileName, (p) =>
                    {
                        ps.SetProgress(p.current, p.total);
                    });
                    ps.SetMessage("完成！");
                    Thread.Sleep(500);
                }, err =>
                {
                    if (err is TranscriptSyntaxException ex)
                    {
                        MessageBox.Show(this, $"发现错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
                        return;
                    }
                    if (err != null)
                    {
                        MessageBox.Show(this, $"合成错误：{err.GetType().Name}：{err.Message}");
                        return;
                    }
                    showMessage("合成完成");
                });
            }
        }

        public void SaveContentTo(List<BaseParamYieldException> data, string filePath, Action<(int current,int total)> progressCallback)
        {
            void setProgress(int current,int total) { 
                if(progressCallback != null)
                {
                    progressCallback((current, total));
                }
            }

            List<ISampleProvider> providers = new List<ISampleProvider>();
            

            Exception composeError = null;

            AwaitComposeAsync(data, (cur, total) =>
            {
                setProgress(cur,total * 2);
            }, (result, err) =>
            {
                if (result != null)
                {
                    providers.AddRange(result);
                }
                else
                {
                    composeError = err;
                }
            });

            if (composeError != null)
            {
                throw composeError;
            }

            setProgress(100, 100);
            ConcatenatingDisposableSampleProvider finalProvider = new ConcatenatingDisposableSampleProvider(providers);
            float[] buffer = new float[2048];
            WaveFileWriter waveFileWriter = new WaveFileWriter(filePath, new WaveFormat(finalProvider.WaveFormat.SampleRate, finalProvider.WaveFormat.Channels));
            int readCount = 0;
            while ((readCount = finalProvider.Read(buffer, 0, buffer.Length)) > 0)
            {
                waveFileWriter.WriteSamples(buffer, 0, readCount);
                setProgress(finalProvider.Current / 2 + finalProvider.Total / 2, finalProvider.Total);
            }

            waveFileWriter.Flush();
            waveFileWriter.Dispose();
            finalProvider.Dispose();
        }

        // 全新的章节功能！brought you by ChatGLM4.6
        public class ChapterInfo
        {
            public string chapterName; // 章节名称，提取##后面的内容并去除首尾空格后实现
            public int lineStart; // 章节开始的一行，含章节定义本身
            public int lineEnd; // 章节的最后一行

            private TextEditor textEditor;

            public ChapterInfo(TextEditor editor, int start, int end, string name)
            {
                textEditor = editor;
                lineStart = start;
                lineEnd = end;
                chapterName = name;
            }

            public bool CheckContentValid()
            {
                // 检查该章节是否有实际的会出声的内容
                // 会出声的内容有：合成内容，[=指令，[sfx指令
                for (int i = lineStart; i <= lineEnd; i++)
                {
                    DocumentLine line = textEditor.Document.GetLineByNumber(i);
                    string lineText = textEditor.Document.GetText(line.Offset, line.Length).Trim();

                    // 跳过空行、注释行和章节定义行
                    if (string.IsNullOrEmpty(lineText) || lineText.StartsWith("#") || lineText.StartsWith("##"))
                        continue;

                    // 检查是否为指令行
                    if (lineText.StartsWith("["))
                    {
                        // 检查是否为会出声的指令
                        if (lineText.StartsWith("[=") || lineText.StartsWith("[sfx"))
                            return true;
                    }
                    else
                    {
                        // 合成内容
                        return true;
                    }
                }
                return false;
            }

            public string GetChapterBeforeContent()
            {
                // 获取从首行到章节第一行之前的所有内容
                StringBuilder result = new StringBuilder();

                for (int i = 1; i < lineStart; i++)
                {
                    DocumentLine line = textEditor.Document.GetLineByNumber(i);
                    string lineText = textEditor.Document.GetText(line.Offset, line.Length);
                    result.AppendLine(lineText);
                }

                return result.ToString();
            }

            public string GetChapterBodyContent()
            {
                // 获取章节本体的内容
                StringBuilder result = new StringBuilder();

                for (int i = lineStart; i <= lineEnd; i++)
                {
                    DocumentLine line = textEditor.Document.GetLineByNumber(i);
                    string lineText = textEditor.Document.GetText(line.Offset, line.Length);
                    result.AppendLine(lineText);
                }

                return result.ToString();
            }
        }

        public List<ChapterInfo> GetAllChapters()
        {
            // 扫描脚本内容，生成章节结构
            List<ChapterInfo> chapters = new List<ChapterInfo>();
            int totalLines = textEditor.Document.LineCount;
            int currentChapterStart = 1;
            string currentChapterName = "[头部信息]";

            for (int i = 1; i <= totalLines; i++)
            {
                DocumentLine line = textEditor.Document.GetLineByNumber(i);
                string lineText = textEditor.Document.GetText(line.Offset, line.Length).Trim();

                // 检查是否为章节定义行
                if (lineText.StartsWith("##"))
                {
                    // 如果不是第一个章节，先添加前一个章节
                    if (i > 1)
                    {
                        ChapterInfo prevChapter = new ChapterInfo(textEditor, currentChapterStart, i - 1, currentChapterName);
                        // 如果是头部章节且没有有效内容，则不添加
                        if (currentChapterName != "[头部信息]" || prevChapter.CheckContentValid())
                        {
                            chapters.Add(prevChapter);
                        }
                    }

                    // 开始新章节
                    currentChapterStart = i;
                    // 提取章节名称（##后面的内容并去除首尾空格）
                    currentChapterName = lineText.Substring(2).Trim();
                }
            }

            // 添加最后一个章节
            if (currentChapterStart <= totalLines)
            {
                ChapterInfo lastChapter = new ChapterInfo(textEditor, currentChapterStart, totalLines, currentChapterName);
                // 如果是头部章节且没有有效内容，则不添加
                if (currentChapterName != "[头部信息]" || lastChapter.CheckContentValid())
                {
                    chapters.Add(lastChapter);
                }
            }

            return chapters;
        }

        public ChapterInfo GetCurrentChapter()
        {
            // 获取光标所在行号
            int selectionStart = textEditor.SelectionStart;
            DocumentLine currentLine = textEditor.Document.GetLineByOffset(selectionStart);
            int currentLineNumber = currentLine.LineNumber;

            // 向上查找最近的章节定义行
            int chapterStartLine = -1;
            string chapterName = "[头部信息]";

            // 从当前行向上查找
            for (int i = currentLineNumber; i >= 1; i--)
            {
                DocumentLine line = textEditor.Document.GetLineByNumber(i);
                string lineText = textEditor.Document.GetText(line.Offset, line.Length).Trim();

                if (lineText.StartsWith("##"))
                {
                    // 找到章节定义行
                    chapterStartLine = i;
                    chapterName = lineText.Substring(2).Trim();
                    break;
                }
            }

            // 如果没有找到章节定义行，则检查是否在头部信息章节中
            if (chapterStartLine == -1)
            {
                // 检查文档中是否有任何章节定义
                bool hasAnyChapter = false;
                for (int i = 1; i <= textEditor.Document.LineCount; i++)
                {
                    DocumentLine line = textEditor.Document.GetLineByNumber(i);
                    string lineText = textEditor.Document.GetText(line.Offset, line.Length).Trim();

                    if (lineText.StartsWith("##"))
                    {
                        hasAnyChapter = true;
                        break;
                    }
                }

                // 如果文档中有章节定义，但光标不在任何章节中，则返回null
                if (hasAnyChapter)
                    return null;

                // 如果文档中没有章节定义，则整个文档都是头部信息章节
                chapterStartLine = 1;
            }

            // 向下查找章节结束行（下一个章节定义行或文档末尾）
            int chapterEndLine = textEditor.Document.LineCount;
            for (int i = chapterStartLine + 1; i <= textEditor.Document.LineCount; i++)
            {
                DocumentLine line = textEditor.Document.GetLineByNumber(i);
                string lineText = textEditor.Document.GetText(line.Offset, line.Length).Trim();

                if (lineText.StartsWith("##"))
                {
                    // 找到下一个章节定义行
                    chapterEndLine = i - 1;
                    break;
                }
            }

            // 创建章节信息对象
            ChapterInfo chapter = new ChapterInfo(textEditor, chapterStartLine, chapterEndLine, chapterName);

            // 如果是头部信息章节且没有有效内容，则返回null
            if (chapterName == "[头部信息]" && !chapter.CheckContentValid())
                return null;

            return chapter;
        }



        private void 导出全部章节ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                // 获取所有章节
                var chapters = GetAllChapters();
                if (chapters.Count == 0)
                {
                    Toast.ShowMessage("没有找到任何章节");
                    return;
                }

                // 弹出保存Zip文件的对话框
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "Zip文件|*.zip";
                saveFileDialog.FileName = "章节导出.zip";
                if (saveFileDialog.ShowDialog(this) != DialogResult.OK)
                {
                    return;
                }
                string zipFileName = saveFileDialog.FileName;

                ProgressDialog.RunWork(this, ps =>
                {
                    // 创建临时目录
                    string tempDir = Path.Combine(Program.cachePath, "chapterOuts", Guid.NewGuid().ToString());
                    Directory.CreateDirectory(tempDir);

                    ps.SetIndetermine(false);
                    ps.SetProgress(0, chapters.Count);

                    // 合成每个章节
                    for (int i = 0; i < chapters.Count; i++)
                    {
                        var chapter = chapters[i];
                        ps.SetMessage($"正在合成第({i + 1}/{chapters.Count})个章节：{chapter.chapterName}");

                        try
                        {

                            string beforeContent = "";
                            string chapterBody = "";
                            Invoke(new Action(() =>
                            {
                                beforeContent = chapter.GetChapterBeforeContent() ?? "";
                                chapterBody = chapter.GetChapterBodyContent() ?? "";
                            }));

                            // 编译脚本
                            ps.SetMessage($"正在编译第({i + 1}/{chapters.Count})个章节：{chapter.chapterName}");
                            var data = new TranscriptEngine().EvaluatePartial(beforeContent, chapterBody);
                            if (data.Count == 0)
                            {
                                throw new Exception($"章节「{chapter.chapterName}」的合成结果是空的。");
                            }

                            // 生成安全的文件名
                            string safeChapterName = chapter.chapterName;
                            var invalidChars = Path.GetInvalidFileNameChars();
                            foreach (char c in invalidChars)
                            {
                                safeChapterName = safeChapterName.Replace(c, '_');
                            }

                            string chapterFileName = Path.Combine(tempDir, safeChapterName + ".wav");

                            // 处理文件名冲突
                            int counter = 1;
                            while (File.Exists(chapterFileName))
                            {
                                chapterFileName = Path.Combine(tempDir, $"{safeChapterName} ({counter}).wav");
                                counter++;
                            }

                            // 合成音频文件
                            ps.SetMessage($"正在合成音频第({i + 1}/{chapters.Count})个章节：{chapter.chapterName}");
                            SaveContentTo(data, chapterFileName, (p) =>
                            {
                                ps.SetProgress(p.current, p.total);
                            });
                        }
                        catch (Exception ex)
                        {
                            // 如果是语法错误，抛出特殊异常
                            if (ex is TranscriptSyntaxException syntaxEx)
                            {
                                throw new Exception($"章节「{chapter.chapterName}」语法错误：{syntaxEx.reason}\r\n在第{syntaxEx.lineNumber}行：\r\n{syntaxEx.lineContent}");
                            }
                            // 其他错误
                            throw new Exception($"章节「{chapter.chapterName}」合成失败：{ex.Message}");
                        }

                        // 更新进度
                        ps.SetProgress(i + 1, chapters.Count);
                    }

                    // 打包成Zip文件
                    ps.SetMessage("正在打包文件...");
                    var fastZip = new ICSharpCode.SharpZipLib.Zip.FastZip();
                    fastZip.CreateEmptyDirectories = false;
                    fastZip.CreateZip(zipFileName, tempDir, false, null);
                    ps.SetMessage("完成！");
                    Thread.Sleep(500);
                }, err =>
                {
                    if (err != null)
                    {
                        MessageBox.Show(this, $"导出错误：{err.Message}");
                    }
                    else
                    {
                        showMessage("全部章节导出完成");
                    }
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }


        private void btnPlayAll_Click(object sender, EventArgs e)
        {
            var chapter = GetCurrentChapter();
            if(chapter == null)
            {
                Toast.ShowMessage("光标未放置在章节定义内");
                return;
            }
            try
            {
                var beforeContent = chapter.GetChapterBeforeContent() ?? "";
                var chapterBody = chapter.GetChapterBodyContent() ?? "";
                PlayContent(new TranscriptEngine().EvaluatePartial(beforeContent,chapterBody));
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }

        private void 导出当前章节ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var chapter = GetCurrentChapter();
            if (chapter == null)
            {
                Toast.ShowMessage("光标未放置在章节定义内");
                return;
            }
            try
            {
                var beforeContent = chapter.GetChapterBeforeContent() ?? "";
                var chapterBody = chapter.GetChapterBodyContent() ?? "";
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "音频文件|*.wav";
                string safeChapterName = chapter.chapterName;
                var invalidChars = Path.GetInvalidFileNameChars();
                invalidChars.ToList().ForEach(c => safeChapterName = safeChapterName.Replace(c, '_'));
                saveFileDialog.FileName = safeChapterName + ".wav";
                if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
                {
                    string fileName = saveFileDialog.FileName;
                    ProgressDialog.RunWork(this, ps =>
                    {
                        ps.SetIndetermine(true);
                        ps.SetMessage("正在编译脚本...");
                        var data = new TranscriptEngine().EvaluatePartial(beforeContent, chapterBody);
                        if (data.Count == 0)
                        {
                            throw new Exception("合成结果是空的。");
                        }
                        ps.SetMessage("开始合成...");
                        SaveContentTo(data, fileName, (p) =>
                        {
                            ps.SetProgress(p.current, p.total);
                        });
                        ps.SetMessage("完成！");
                        Thread.Sleep(500);
                    }, err =>
                    {
                        if (err is TranscriptSyntaxException ex)
                        {
                            MessageBox.Show(this, $"发现错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
                            return;
                        }
                        if (err != null)
                        {
                            MessageBox.Show(this, $"合成错误：{err.GetType().Name}：{err.Message}");
                            return;
                        }
                        showMessage("合成完成");
                    });
                }
            }
            catch (TranscriptSyntaxException ex)
            {
                MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"未知错误：{ex.Message}");
            }
        }
        private void tblLeftArea_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(tblLeftArea.SelectedIndex == 2)
            {
                btnReloadChapterList_LinkClicked(null, null);
            }
        }


        private void initChapterList()
        {
            tblChapterList.ImageList = listIcons;
        }

        private void btnReloadChapterList_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            tblChapterList.BeginUpdate();
            tblChapterList.Nodes.Clear();
            var chapters = GetAllChapters();
            foreach (var item in chapters)
            {
                TreeNode tn = new TreeNode();
                tn.ImageIndex = 1;
                tn.SelectedImageIndex = 1;
                tn.Text = item.chapterName;
                tn.Tag = item;
                tblChapterList.Nodes.Add(tn);
            }
            tblChapterList.EndUpdate();
        }

        private ChapterInfo _selectedChapter = null;

        private void tblChapterList_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            tblChapterList.SelectedNode = e.Node;
            if (e.Button == MouseButtons.Right)
            {
                _selectedChapter = e.Node.Tag as ChapterInfo;
                if(_selectedChapter != null)
                {
                    mnuChapters.Show(tblChapterList, e.Location);
                }
            }
        }
        private void tblChapterList_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            _selectedChapter = e.Node.Tag as ChapterInfo;
            if (_selectedChapter != null)
            {
                mnuGotoChapter_Click(null,null);
            }
        }

        private void mnuGotoChapter_Click(object sender, EventArgs e)
        {
            if(_selectedChapter != null)
            {
                textEditor.ScrollTo(_selectedChapter.lineStart,0);
                textEditor.Focus();
            }
        }

        private void mnuPreviewChapter_Click(object sender, EventArgs e)
        {
            if(_selectedChapter != null)
            {
                try
                {
                    var beforeContent = _selectedChapter.GetChapterBeforeContent() ?? "";
                    var chapterBody = _selectedChapter.GetChapterBodyContent() ?? "";
                    PlayContent(new TranscriptEngine().EvaluatePartial(beforeContent, chapterBody));
                }
                catch (TranscriptSyntaxException ex)
                {
                    MessageBox.Show(this, $"语法错误：{ex.reason}\r\n在第{ex.lineNumber}行：\r\n{ex.lineContent}");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(this, $"未知错误：{ex.Message}");
                }
            }
        }

        
    }
}
